package br.com.monitorimoveis.batch.parser;

import java.util.ArrayList;
import java.util.List;

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import br.com.monitorimoveis.batch.Contexto;
import br.com.monitorimoveis.comum.entidade.Anuncio;
import br.com.monitorimoveis.comum.entidade.Bairro;
import br.com.monitorimoveis.comum.entidade.Cidade;
import br.com.monitorimoveis.comum.entidade.InfoColeta;
import br.com.monitorimoveis.comum.entidade.TipoAnuncio;
import br.com.monitorimoveis.comum.entidade.TipoImovel;
import br.com.monitorimoveis.comum.servico.IBairroService;
import br.com.monitorimoveis.comum.servico.ICidadeService;
import br.com.monitorimoveis.comum.servico.ITipoAnuncioService;
import br.com.monitorimoveis.comum.servico.ITipoImovelService;
import br.com.monitorimoveis.comum.util.Convert;
import br.com.monitorimoveis.comum.util.StringUtils;

@Service
public class WImoveisParser {

	private ITipoImovelService servicoTipoImovel = (ITipoImovelService) Contexto
			.get().getBean("tipoImovelService");
	private ITipoAnuncioService servicoTipoAnuncio = (ITipoAnuncioService) Contexto
			.get().getBean("tipoAnuncioService");
	private IBairroService servicoBairro = (IBairroService) Contexto.get()
			.getBean("bairroService");
	private ICidadeService servicoCidade = (ICidadeService) Contexto.get()
			.getBean("cidadeService");

	private static String urlBase = "http://www.wimoveis.com.br";

	/**
	 * Realiza o parse de um Document, originado de uma pagina web, extraindo
	 * dela as informações de um Anuncio.
	 * 
	 * @param paginaAnuncio
	 * @return
	 * @throws Exception
	 */
	
	@Transactional
	public Anuncio parse(Document paginaAnuncio, String url) throws Exception {
		Anuncio anuncio = new Anuncio();

		// String localizacao = paginaAnuncio.select("#literalIdentificacao")
		// .first().text().toUpperCase();

		TipoAnuncio tipoAnuncio = null;

		if (url.contains("Venda") || url.contains("venda")
				|| url.contains("VENDA")) {
			tipoAnuncio = servicoTipoAnuncio.recuperarPorDescricao("VENDA");
		} else if (url.contains("Aluguel") || url.contains("aluguel")
				|| url.contains("ALUGUEL")) {
			tipoAnuncio = servicoTipoAnuncio.recuperarPorDescricao("ALUGUEL");
		}

		anuncio.setTipoAnuncio(tipoAnuncio);

		int ultimoHifen = url.lastIndexOf("-");

		if (ultimoHifen > 0) {
			String codigo = url.substring(ultimoHifen + 1);
			anuncio.setCodigo(Convert.strToInt(codigo));
		}

		String identificacao = paginaAnuncio.select("#literalIdentificacao")
				.first().text();

		System.out.println("Selecionei #literalIdentificacao");
		anuncio.setIdentificacao(identificacao);

		Element divDadosPrincipais = paginaAnuncio.select(".dados_principais")
				.first();

		System.out.println("Selecionei .dados_principais");
		
		Elements selecao = divDadosPrincipais.select("p");

		System.out.println("Selecionei paragrafos");
		
		parseDadosPrincipais(selecao.text(), anuncio);

		selecao = paginaAnuncio.select(".dado_adicional:eq(2) p");
		
		System.out.println("Selecionei .dado_adicional:eq(2) p");
		
		StringBuffer buffer = new StringBuffer();

		for (Element element : selecao) {
			buffer.append(element.text());
		}

		parseDadosAdicionais(buffer.toString(), anuncio);

		System.out.println("Terminei parse do anuncio de codigo " + anuncio.getCodigo());
		
		return anuncio;
	}

	/**
	 * Obtem os dados de coleta do anuncio a partir de um elemento HTML. É usado
	 * para interpretar cada resultado de pesquisa e guarda-lo para consultar a
	 * página do anuncio posteriormente.
	 * 
	 * @param tagAnuncio
	 * @return
	 * @throws Exception
	 */
	public InfoColeta obterURLColetaAnuncio(Element tagAnuncio)
			throws Exception {
		InfoColeta infoColeta = new InfoColeta();

		Element e = tagAnuncio.select("a").first();

		String url = e.attr("href");
		infoColeta.setUrl(urlBase + url);

		int codigo = extrairCodigoDaURL(url);
		infoColeta.setCodAnuncio(codigo);

		infoColeta.setColetado(false);

		Elements els = tagAnuncio.select(".info_galeria b");

		if (els != null && els.size() >= 2) {
			String dataAtualizacao = els.get(1).text();
			infoColeta.setData(Convert.strToDate(dataAtualizacao));
		}

		return infoColeta;
	}

	private void parseDadosPrincipais(String dados, Anuncio anuncio) {

		String valor = anuncio.getTipoAnuncio().getDescricao()
				.equalsIgnoreCase("VENDA") ? "Valor Total do Imóvel R$:"
				: "Valor Total do Aluguel R$:";
		String[] arrayDelimitadores = new String[] { "Código:", "Data:",
				"Localização:", "Cidade:", "Bairro:", "Tipo:", "Quartos:",
				"Suites:", "Garagens:", "Elevador:", valor, "Valor m² R$:",
				"Gráfico Ágio:", "Área Útil:", "Aceita Financiar:" };

		System.out.println("Dentro do parseDadosPrincipais");
		List<String> tokens = criarTokens(dados, arrayDelimitadores);

		// for (String token : tokens) {
		// System.out.println("Token: " + token);
		// }

		anuncio.setDataAtualizacao(Convert.strToDate(tokens.get(1)));
		anuncio.setLocalizacao(tokens.get(2));

		// anuncio.setCidade(tokens.get(3));

		System.out.println("Vou pesquisar a cidade...");
		
		Cidade cidade = servicoCidade.pesquisarPorNome(tokens.get(3)).get(0);
		
		System.out.println("Pesquisei a cidade: " + cidade.getNome());
		
		Bairro bairro = servicoBairro.recuperarPorCidadeENome(cidade,
				tokens.get(4));

		System.out.println("Pesquisei o bairro: " + bairro.getNome());
		
		anuncio.setBairro(bairro);

		TipoImovel tipoImovel = servicoTipoImovel.recuperarPorDescricao(tokens
				.get(5));
		
		System.out.println("Recuperei o tipo do imovel: " + tipoImovel.getDescricao());
		anuncio.setTipoImovel(tipoImovel);

		anuncio.setQuartos(Convert.strToInt(tokens.get(6)));
		anuncio.setSuites(Convert.strToInt(tokens.get(7)));
		anuncio.setVagas(Convert.strToInt(tokens.get(8)));
		anuncio.setElevadores(Convert.strToInt(tokens.get(9)));
		anuncio.setPreco(Convert.strToDoubleWithFormat(tokens.get(10)));

		String agio = tokens.get(11).replace("R$", "");

		anuncio.setPrecoAgio(Convert.strToDoubleWithFormat(agio));
		anuncio.setPrecoM2(Convert.strToDoubleWithFormat(tokens.get(12)));
		anuncio.setAreaUtil(Convert.strToDoubleWithFormat(tokens.get(13)));
		anuncio.setAceitaFinanciamento(Convert.strToBool(tokens.get(14)));

		System.out.println("Sai do parseDadosPrincipais");
	}

	private void parseDadosAdicionais(String dados, Anuncio anuncio) {

		String[] arrayDelimitadores = new String[] { "Imóvel Pronto:",
				"Área do Terreno:", "Área Total:", "Andar:", "Andares:",
				"Posição do Apto:", "Posição do Sol:", "Condomínio R$:" };

		System.out.println("Dentro do parseDadosAdicionais");
		List<String> tokens = criarTokens(dados, arrayDelimitadores);

		// for (String token : tokens) {
		// System.out.println("Token: " + token);
		// }

		anuncio.setPronto(tokens.get(0).equalsIgnoreCase("SIM") ? true : false);
		anuncio.setAreaTerreno(Convert.strToDouble(tokens.get(1)));
		anuncio.setAreaTotal(Convert.strToDoubleWithFormat(tokens.get(2)));
		anuncio.setAndar(Convert.strToInt(tokens.get(3)));
		anuncio.setAndares(Convert.strToInt(tokens.get(4)));
		anuncio.setPosicao(tokens.get(5));
		anuncio.setPosicaoSol(tokens.get(6));
		anuncio.setPrecoCondominio(Convert.strToDoubleWithFormat(tokens.get(7)));
		
		System.out.println("Sai do parseDadosAdicionais");

	}

	private List<String> criarTokens(String dados, String[] arrayDelimitadores) {

		List<String> tokens = new ArrayList<String>();

		System.out.println("Dados:\n" + dados);

		for (int i = 0; i < arrayDelimitadores.length; i++) {

			int indInicio, indFim = 0;
			String token = "";

			indInicio = dados.indexOf(arrayDelimitadores[i])
					+ arrayDelimitadores[i].length();

			if (i == arrayDelimitadores.length - 1) {
				token = dados.substring(indInicio);
			} else {
				indFim = dados.indexOf(arrayDelimitadores[i + 1]);
				token = dados.substring(indInicio, indFim);
			}

			token = StringUtils.trimStr(token, (char) 160, ' ');
			tokens.add(token.replace("m²", ""));
			System.out.println("Token: " + token + " | ");
		}
		
		System.out.println("Finalizei com tokens");
		return tokens;
	}

	/**
	 * No Wimoveis, o código do anúncio é exibido no final da URL. Esse método
	 * extrai o código do anuncio a partir da URL.
	 * 
	 * @param url
	 * @return
	 */
	private int extrairCodigoDaURL(String url) {

		String codAsStr = url.substring(url.lastIndexOf("-") + 1);

		return Integer.valueOf(codAsStr);
	}
	//
	// /**
	// * Faz o parse de cada anuncio contido na pagina de resultado de pesquisa.
	// * @param tagAnuncio
	// * @return
	// * @throws Exception
	// */
	// public static Anuncio parse(Element tagAnuncio) throws Exception {
	//
	// Anuncio anuncio = new Anuncio();
	//
	// Elements elements = tagAnuncio.select(".localizacaoBairro a");
	//
	// int index = 0;
	// if (elements.size() == 2) {
	// index = 1;
	// }
	//
	// Element e = elements.get(index);
	//
	// anuncio.setLocalizacao(e.text());
	//
	// Elements icones = tagAnuncio.select(".icones");
	//
	// anuncio.setQuartos(Convert.strToInt(icones.get(0).text()));
	// anuncio.setSuites(Convert.strToInt(icones.get(1).text()));
	// anuncio.setVagas(Convert.strToInt(icones.get(2).text()));
	//
	// String areaAsStr = tagAnuncio.select(".m2").first().text();
	// areaAsStr = areaAsStr.substring(1);
	// areaAsStr = areaAsStr.replace(",", ".");
	//
	// anuncio.setAreaUtil(Convert.strToDouble(areaAsStr));
	//
	// String valorAsStr = tagAnuncio.select(".valor a b").first().text();
	// valorAsStr = valorAsStr.replace(".", "");
	// valorAsStr = valorAsStr.replace(",", ".");
	//
	// anuncio.setPreco(Convert.strToDouble((valorAsStr)));
	//
	// // String valorM2AsStr =
	// // tagAnuncio.select(".valor font").first().text();
	// // valorM2AsStr = valorM2AsStr.replace("Valor m²: ", "").replace(".",
	// // "").replace(",", ".");
	// // anuncio.setValorM2(strToDouble(valorM2AsStr));
	//
	// double precoMetro = anuncio.getPreco() / anuncio.getAreaUtil();
	// anuncio.setPrecoM2(Precision.round(precoMetro, 2));
	// return anuncio;
	// }

}
